package c_processPkg

import (
	"Infinichat_mixed/entity"
	"Infinichat_mixed/transfer"
	"bufio"
	"encoding/json"
	"fmt"
	"net"
	"os"
	"strconv"
	"strings"
	"time"
)

func ShowMenu() {
	// sms实例能被重复使用，因此可以定义在外部
	smsProces := &SmsProcess{}

label:
	for true {
		fmt.Println("--------------------- user selection ---------------------")
		fmt.Println("--------------------- 1. show user list ---------------------")
		fmt.Println("--------------------- 2. add user ---------------------")
		fmt.Println("--------------------- 3. friend request ---------------------")
		fmt.Println("--------------------- 4. send msg to all(broadcast)      ---------------------")
		fmt.Println("--------------------- 5. send msg to someone(p2p)       ---------------------")
		fmt.Println("--------------------- 6. logout       ---------------------")
		fmt.Println("--------------------- 7. exit system    ---------------------")
		fmt.Println("--------------------- 8. create group    ---------------------")
		fmt.Println("--------------------- 9. send to group    ---------------------")
		fmt.Println("--------------------- 10. group invite    ---------------------")
		fmt.Println("--------------------- 11. set up scheduled task sending    ---------------------")
		fmt.Print("Please input:")
		var key int
		_, err := fmt.Scanf("%d\n", &key)
		if err != nil {
			reader := bufio.NewReader(os.Stdin)
			reader.ReadString('\n') // 读取缓冲区并丢弃，不然输出多个错误时会触发多次
		}

		switch key {
		case 1:
			outputOnlineUser()
		case 2:
			// 首先 输入 nickname 返回用户  (模糊查询)
			var nickname string
			fmt.Print("Please input the nickname:")
			fmt.Scanf("%s\n", &nickname)

			var mes entity.Message
			mes.Type = entity.AskForUsersType
			var fu_mes entity.FindUserByNameMes
			fu_mes.UserId = CurUser.ID
			fu_mes.FindName = nickname
			data, err := json.Marshal(fu_mes)
			if err != nil {
				fmt.Println(err)
			}
			mes.Data = string(data)
			data, err = json.Marshal(mes)
			tf := &transfer.Transfer{
				Conn: CurConn,
			}
			err = tf.WriterPkg(data)
			if err != nil {
				fmt.Println(err)
			}
			users := &[]entity.User{}
			// 这里进行阻塞 反复去读取chan中的消息 直到读取到
			is_read := true
			for is_read {
				select {
				case data := <-askforUsers:
					err := json.Unmarshal([]byte(data), &users)
					if err != nil {
						fmt.Println(err)
					}
					is_read = false
				}
			}
			fmt.Println("users:", users)
			// 选择想添加的好友的ID
			fmt.Print("Please input the ID to add:")
			var addId uint
			fmt.Scanf("%d\n", &addId)
			// 然后 根据addId和当前userId 在friend中先确认是否为好友
			var mes2 entity.Message
			mes2.Type = entity.IsFriendType
			var if_mes entity.IsFriendMes
			if_mes.SourceId = CurUser.ID
			if_mes.TargetId = addId
			if_mes.Flag = false // 传过去假设不是好友
			data, err = json.Marshal(if_mes)
			if err != nil {
				fmt.Println(err)
			}
			mes2.Data = string(data)
			data, err = json.Marshal(mes2)
			if err != nil {
				fmt.Println(err)
			}
			err = tf.WriterPkg(data)
			if err != nil {
				fmt.Println(err)
			}

			is_read = true
			for is_read {
				select {
				case data := <-askforUsers:
					err := json.Unmarshal([]byte(data), &if_mes)
					if err != nil {
						fmt.Println(err)
					}
					is_read = false
				}
			}

			if if_mes.Flag == true {
				fmt.Println("已发起添加请求!")
				fmt.Println("你和Ta有这些共同好友：", if_mes.MutualFriend)
			} else {
				fmt.Println(if_mes.Msg)
			}
		case 3:
			// 查出所有好友请求
			var mes entity.Message
			mes.Type = entity.FindFriedAddType
			mes.Data = strconv.Itoa(int(CurUser.ID))
			data, err := json.Marshal(mes)
			if err != nil {
				fmt.Println(err)
			}
			tf := &transfer.Transfer{
				Conn: CurConn,
			}
			err = tf.WriterPkg(data)
			if err != nil {
				fmt.Println(err)
			}
			friends := []entity.Friend{}
			is_read := true
			for is_read {
				select {
				case data := <-askforUsers:
					err := json.Unmarshal([]byte(data), &friends)
					if err != nil {
						fmt.Println(err)
					}
					is_read = false
				}
			}
			fmt.Println("friends want to add you:")
			for _, v := range friends {
				fmt.Print(v.Sid, " ")
			}
			fmt.Print("\nPlease input the ID to add:")
			var addId uint
			fmt.Scanf("%d\n", &addId)
			mes.Type = entity.Select2AddType
			tmp := entity.IsFriendMes{}
			tmp.SourceId = addId
			tmp.TargetId = CurUser.ID
			tmp.Flag = true
			data, err = json.Marshal(tmp)
			mes.Data = string(data)
			data, err = json.Marshal(mes)
			err = tf.WriterPkg(data)
			if err != nil {
				fmt.Println(err)
			}
			is_read = true
			for is_read {
				select {
				case data := <-askforUsers:
					fdData := entity.FriendAdd{}
					err := json.Unmarshal([]byte(data), &fdData)
					if err != nil {
						fmt.Println(err)
					}
					if fdData.Status == 0 {
						fmt.Println("Add fail.")
					} else {
						fmt.Println("Add success.")
						// 如果对方在线，则需要添加到在线好友列表
						if fdData.Status == 1 {
							// 通过好友的添加请求，应该是SourceId
							fmt.Printf("好友%d上线\n", tmp.SourceId)
							Friend := &entity.User{}
							Friend.ID = tmp.SourceId
							Friend.UserStatus = entity.UserOnline
							OnlineUsers[tmp.SourceId] = Friend
						}
					}
					is_read = false
				}
			}
		case 4:
			var content string
			fmt.Print("Please input the message to all:")
			//fmt.Scanf("%s\n", &content)		// 无法识别"hello world" 原因：带有空格的后面语句会被视为下一句
			reader := bufio.NewReader(os.Stdin)
			content, _ = reader.ReadString('\n')
			smsProces.SendBroadcastEMs(content)
		case 5:
			// 先发送查询请求 查看当前用户有多少好友
			var mes entity.Message
			mes.Type = entity.FindFriendType
			var FindFriendAddMes entity.FindFriendAddMes
			FindFriendAddMes.SourceId = CurUser.ID
			data, _ := json.Marshal(FindFriendAddMes)
			mes.Data = string(data)
			data, _ = json.Marshal(mes)
			tf := &transfer.Transfer{
				Conn: CurConn,
			}
			_ = tf.WriterPkg(data)
			is_read := true
			for is_read {
				select {
				case data := <-askforUsers:
					err := json.Unmarshal([]byte(data), &FindFriendAddMes)
					if err != nil {
						fmt.Println(err)
					}
					is_read = false
				}
			}
			// 选择ID进行消息发送
			FriedIds := []uint{}
			for _, f := range FindFriendAddMes.Friends {
				FriedIds = append(FriedIds, f.ID)
			}
			fmt.Println("你的好友为:", FriedIds)
			var target_id uint
			var content string
			fmt.Print("选择一个好友的id进行聊天:")
			fmt.Scanf("%d\n", &target_id)
			// 找出与该好友的所有聊天记录
			mes.Type = entity.ChattingRecType
			mesMp := make(map[string]interface{})
			mesMp["sId"] = CurUser.ID
			mesMp["tId"] = target_id
			mesMpData, _ := json.Marshal(mesMp)
			mes.Data = string(mesMpData)
			data, _ = json.Marshal(mes)
			_ = tf.WriterPkg(data)

			var p2pMsgs []entity.P2PMsg
			is_read = true
			for is_read {
				select {
				case data := <-askforUsers:
					err := json.Unmarshal([]byte(data), &p2pMsgs)
					if err != nil {
						fmt.Println(err)
					}
					is_read = false
				}
			}
			fmt.Printf("之前一共有%d条聊天记录：\n", len(p2pMsgs))
			for _, p2pMsg := range p2pMsgs {
				timeFormat := p2pMsg.CreatedAt.Format("2006-01-02 15:04:05")
				fmt.Printf("时间：%s, 发送人：%d, 接收人：%d, 内容：%s \n", timeFormat, p2pMsg.SendId, p2pMsg.ReceiveId, p2pMsg.Content)
			}

			fmt.Printf("请输入你要发送的内容 %d:\n", target_id)
			reader := bufio.NewReader(os.Stdin)
			content, _ = reader.ReadString('\n')
			//smsProces.Send2one(target_id, content)
			send2Multiple([]uint{target_id}, content)

		case 6, 7:
			id := CurUser.User.ID
			var mes entity.Message
			mes.Type = entity.LogoutType
			var logoutMes entity.LogoutMes
			logoutMes.Id = id
			mesData, _ := json.Marshal(logoutMes)
			mes.Data = string(mesData)
			data, err := json.Marshal(mes)
			tf := &transfer.Transfer{
				Conn: CurConn,
			}
			err = tf.WriterPkg(data)
			if err != nil {
				fmt.Println(err)
				fmt.Println("User logout failed")
			} else {
				delete(OnlineUsers, id)
				fmt.Println("User logout success")
			}
			break label
		case 8:
			fmt.Print("Group name:")
			var groupName string
			fmt.Scanf("%s\n", &groupName)
			fmt.Print("Group Member ID:")
			var tmp string
			fmt.Scanf("%s\n", &tmp)
			strs := strings.Split(tmp, ",")
			var gids entity.MemberIds
			for _, v := range strs {
				num, err := strconv.Atoi(strings.TrimSpace(v))
				if err != nil {
					fmt.Println(err)
				}
				gids = append(gids, uint(num))
			}
			g := &entity.Group{
				GroupName: groupName,
				OwnerUser: CurUser.User.ID,
				Members:   gids,
			}
			var mes entity.Message
			mes.Type = entity.CreateGroupType
			data, err := json.Marshal(g)
			if err != nil {
				fmt.Println(err)
			}
			mes.Data = string(data)
			data, err = json.Marshal(mes)
			tf := &transfer.Transfer{
				Conn: CurConn,
			}
			err = tf.WriterPkg(data)
			if err != nil {
				fmt.Println(err)
			}
		case 9:
			var mes entity.Message
			mes.Type = entity.FindGroupType
			mes.Data = strconv.Itoa(int(CurUser.Model.ID))
			data, err := json.Marshal(mes)
			if err != nil {
				fmt.Println(err)
			}
			tf := &transfer.Transfer{
				Conn: CurConn,
			}
			err = tf.WriterPkg(data)
			if err != nil {
				fmt.Println(err)
			}

			g_ids := []uint{}
			is_read := true
			for is_read {
				select {
				case data := <-askforUsers:
					err := json.Unmarshal([]byte(data), &g_ids)
					if err != nil {
						fmt.Println(err)
					}
					is_read = false
				}
			}
			fmt.Println("Your group:", g_ids)
			fmt.Print("Please select group id to send:")
			var gid uint
			fmt.Scanf("%d\n", &gid)
			var content string
			fmt.Print("Please input content:")
			fmt.Scanf("%s\n", &content)
			smg := &entity.SmsMes2Group{
				Gid:     gid,
				Content: content,
				User:    CurUser.User,
			}
			mes.Type = entity.SmsMes2GroupType
			data, err = json.Marshal(smg)
			mes.Data = string(data)
			data, err = json.Marshal(mes)
			err = tf.WriterPkg(data)
			if err != nil {
				fmt.Println(err)
			}

		case 10:
			// 发送GI检索请求
			var mes entity.Message
			mes.Type = entity.FindGIType
			mesData := make(map[string]interface{}, 1)
			mesData["MemberId"] = CurUser.User.ID
			mesDataMarshal, _ := json.Marshal(mesData)
			mes.Data = string(mesDataMarshal)
			data, err := json.Marshal(mes)
			tf := &transfer.Transfer{
				Conn: CurConn,
			}
			err = tf.WriterPkg(data)
			if err != nil {
				fmt.Println(err)
			}
			is_read := true
			gs := &[]entity.Group{}
			for is_read {
				select {
				case data := <-askforUsers:
					err := json.Unmarshal([]byte(data), &gs)
					if err != nil {
						fmt.Println(err)
					}
					is_read = false
				}
			}
			fmt.Println("These group invite you:", gs)
			fmt.Println("Please input the group you accept/refused:")
			var gid uint
			fmt.Scanf("%d\n", &gid)
			var IsRefused uint
			fmt.Println("Please input accept(1)/refused(0):")
			fmt.Scanf("%t\n", &IsRefused)
			gi := &entity.GroupInvite{
				GroupId:   gid,
				MemberId:  CurUser.User.ID,
				IsRefused: IsRefused,
			}
			mes.Type = entity.AcceptGIType
			data, err = json.Marshal(gi)
			if err != nil {
				fmt.Println(err)
			}
			mes.Data = string(data)
			data, err = json.Marshal(mes)
			if err != nil {
				fmt.Println(err)
			}
			err = tf.WriterPkg(data)
		case 11:
			var message entity.Message
			message.Type = entity.TimeSendType
			var ts entity.TimeSend
			var receiverId uint
			var SendTime time.Duration
			var msg string
			fmt.Print("你要发给谁：")
			fmt.Scanf("%d\n", &receiverId)
			fmt.Print("你要多久后发送：")
			fmt.Scanf("%d\n", &SendTime)
			fmt.Print("你要发的消息：")
			fmt.Scanf("%s\n", &msg)
			ts.SendId = CurUser.User.ID
			ts.RecvId = receiverId
			ts.Msg = msg
			ts.Time = SendTime
			data, _ := json.Marshal(ts)
			message.Data = string(data)

			sendData, _ := json.Marshal(message)
			tf := &transfer.Transfer{
				Conn: CurConn,
			}
			_ = tf.WriterPkg(sendData)

		default:
			fmt.Println("error input!")
		}
	}

}

var askforUsers = make(chan string, 1)

// 和服务器保持通讯
func serverProcessMes(Conn net.Conn) {
	tf := &transfer.Transfer{
		Conn: Conn,
	}
	// 这里传入的是users的json
	for {
		//fmt.Println("client waiting.")
		mes, err := tf.ReadPkg()
		if err != nil {
			fmt.Println("read pkg error:", err)
			return
		}
		//fmt.Println("msg=", mes)
		switch mes.Type {
		case entity.NotifyUserStatusMesType:
			//fmt.Println("enter notify others:", mes)
			var notifyUserStatusMes entity.NotifyUserStatusMes
			json.Unmarshal([]byte(mes.Data), &notifyUserStatusMes)
			updateUserStatus(&notifyUserStatusMes)
		case entity.AskForUsersType, entity.IsFriendType,
			entity.FindFriedAddType, entity.Select2AddType,
			entity.FindFriendType, entity.FindGIType, entity.FindGroupType, entity.ChattingRecType:
			// 这里拿到消息后 让这个消息进入管道 然后上面会一直读取这个消息管道的内容 直到读取到
			// 其他情况都是为了复用这个管道
			askforUsers <- mes.Data
		case entity.SmsMesType:
			// broadcast message
			outputGroupMes(mes)
		case entity.SmsMes2OneType:
			// peer to peer
			outputP2PMes(mes)
			// 标记为已读
			var p2pMesRead entity.Message
			p2pMesRead.Type = entity.NoteP2PReadType

			var smsOneMes entity.P2PMsg
			_ = json.Unmarshal([]byte(mes.Data), &smsOneMes)
			P2pMsgs := []entity.P2PMsg{}
			P2pMsgs = append(P2pMsgs, smsOneMes)
			mesData, _ := json.Marshal(P2pMsgs)
			p2pMesRead.Data = string(mesData)
			data, _ := json.Marshal(p2pMesRead)
			_ = tf.WriterPkg(data)
		case entity.NotifyUserAddType:
			var n_ua = &entity.NotifyUserAdd{}
			json.Unmarshal([]byte(mes.Data), n_ua)
			if n_ua.TargetId == CurUser.User.ID {
				fmt.Printf("ID为%d的用户请求添加你为好友\n", n_ua.SourceId)
			}
		case entity.FriendAddType:
			// 有在线好友通过请求，需要将他加入到在线好友列表
			var mnData = make(map[string]interface{}, 0)
			json.Unmarshal([]byte(mes.Data), &mnData)
			Friend := &entity.User{}
			FriendId := uint(mnData["FriendId"].(float64))
			Friend.ID = FriendId
			Friend.UserStatus = entity.UserOnline
			OnlineUsers[FriendId] = Friend
			fmt.Printf("好友ID为%d通过了你的添加请求", FriendId)
		case entity.NotifyGroupAddType:
			gi := &entity.GroupInvite{}
			json.Unmarshal([]byte(mes.Data), gi)
			fmt.Printf("群主Id为%d邀请你加入群聊<%d>\n", gi.OwnerUser, gi.GroupId)
		case entity.SmsMes2GroupType:
			var gm entity.GroupMsg
			json.Unmarshal([]byte(mes.Data), &gm)
			fmt.Printf("发送人%d在群%d发送了消息%s\n", gm.SenderId, gm.GroupId, gm.Content)
			// 标记为已读
			note2read(Conn, &gm)
		case entity.HeartBeatType:
			// 心跳包，原路回复即可
			fmt.Println("PONG!")
			data, _ := json.Marshal(mes)
			_ = tf.WriterPkg(data)
		default:
			fmt.Println("server return unknown type!")
		}
	}
}

func note2read(Conn net.Conn, gm *entity.GroupMsg) {
	var mes entity.Message
	mes.Type = entity.NoteGmReadType
	mesData, _ := json.Marshal(gm)
	mes.Data = string(mesData)
	tf := &transfer.Transfer{
		Conn: Conn,
	}
	data, _ := json.Marshal(mes)
	_ = tf.WriterPkg(data)
}

func send2Multiple(targetIds []uint, content string) {
	for _, id := range targetIds {
		SendChan <- &SO{
			target_id: id,
			content:   content,
		}
	}
}
